package cn.xy.base.server.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SecureUtil;
import cn.xy.base.server.config.OSSConfig;
import cn.xy.base.server.po.SysAttachment;
import cn.xy.base.server.service.SysAttachmentService;
import cn.xy.base.server.service.UploadService;
import cn.xy.base.server.utils.ImgTypeUtil;
import cn.xy.commons.constant.Consts;
import cn.xy.commons.exception.JzRuntimeException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.UUID;

/**
 * 阿里云oss上传
 *
 *  @author xy
 */
@Slf4j
@Service("ossUploadService")
public class OssUploadServiceImpl implements UploadService {

    @Autowired
    private OSSConfig ossConfig;

    @Autowired
    private SysAttachmentService sysAttachmentService;

    private static final String ERROR_MSG = "文件上传出错=>";

    @Override
    public String upload(MultipartFile file) {
        return this.upload(file, ossConfig.getPath(), false);
    }

    @Override
    public String upload(MultipartFile file, String basePath, boolean generateCompress) {
        try {
            return this.upload(file.getInputStream(), file.getOriginalFilename(), basePath, false);
        } catch (IOException e) {
            log.error(ERROR_MSG, e);
            throw new JzRuntimeException("文件上传失败");
        }
    }

    @Override
    public String upload(InputStream inputStream, String filename) {
        return this.upload(inputStream, filename, ossConfig.getPath(), false);
    }

    @Override
    public String upload(InputStream inputStream, String filename, String basePath, boolean generateCompress) {
        //初始化服务端
        OSS client = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
        //判断桶是否存在
        String bucketName = ossConfig.getBucketName();
        if (!client.doesBucketExist(bucketName)) {
            client.createBucket(bucketName);
        }
        InputStream input = null;
        byte[] fileBytes = IoUtil.readBytes(inputStream, false);
        try (ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileBytes)) {
            // 是否重复上传
            String sha1 = SecureUtil.sha1(new ByteArrayInputStream(fileBytes));
            SysAttachment attachment = sysAttachmentService.getBySha1(sha1);
            if (attachment != null) {
                return attachment.getPath();
            }
            // 处理图片名称与保存路径
            String suffix = FileUtil.extName(filename);
            String filePrefix = UUID.randomUUID().toString();
            String newFileName = filePrefix + Consts.DOT + suffix;
            String thumbFileName = filePrefix + "_thumb." + suffix;
            String date = DateUtil.format(new Date(), "yyyy-MM-dd");
            String savePath = (basePath == null ? "" : basePath + Consts.SLASH) + date + Consts.SLASH;
            String path = savePath + newFileName;
            ObjectMetadata objectMetadata = new ObjectMetadata();
            client.putObject(ossConfig.getBucketName(), path, fileInputStream, objectMetadata);
            String fileUrl = ossConfig.getAccessUrl() + Consts.SLASH + path;
            log.info("file->{},fileUrl->{}", path, fileUrl);
            // 缩略图生成
            String compressPath = "";
            if (generateCompress) {
                inputStream = new ByteArrayInputStream(fileBytes);
                String type = FileTypeUtil.getType(inputStream);
                if (ImgTypeUtil.isImage(type)) {
                    compressPath = savePath + thumbFileName;
                    inputStream = new ByteArrayInputStream(fileBytes);
                    Image compress = this.generateCompress(inputStream);
                    if (compress != null) {
                        input = ImgUtil.toStream(compress, ImgUtil.IMAGE_TYPE_PNG);
                        client.putObject(ossConfig.getBucketName(), compressPath, input, objectMetadata);
                    }
                }
            }
            // 保存上传记录
            attachment = new SysAttachment();
            attachment.setName(filename);
            attachment.setSha1(sha1);
            attachment.setPath(path);
            attachment.setUrlPath(fileUrl);
            attachment.setCompressPath(compressPath);
            attachment.setCreateTime(DateUtil.date());
            //保存之前在查询一次
            SysAttachment oldAttachment = sysAttachmentService.getBySha1(sha1);
            if (oldAttachment != null) {
                return oldAttachment.getPath();
            }
            sysAttachmentService.save(attachment);
            return path;
        } catch (Exception e) {
            log.error(ERROR_MSG, e);
        } finally {
            client.shutdown();
            try {
                inputStream.close();
            } catch (IOException e) {
                log.error(ERROR_MSG, e);
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    log.error(ERROR_MSG, e);
                }
            }
        }
        throw new JzRuntimeException("文件上传失败");
    }

    @Override
    public Image generateCompress(InputStream inputStream) {
        int min = 300;
        try {
            BufferedImage bufferedImage = ImgUtil.read(inputStream);
            // 如果图片宽已经小于min的值不再压缩
            if (bufferedImage.getWidth() < min) {
                return bufferedImage;
            }
            int height = bufferedImage.getHeight() * min / bufferedImage.getWidth();
            return ImgUtil.scale(bufferedImage, min, height);
        } catch (Exception e) {
            log.error("压缩图片/缩略图片生成失败=> {}", e.getMessage());
        }
        return null;
    }

    @Override
    public byte[] getByteByUrl(String url) {
        OSS client = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
        try {
            InputStream inputStream = client.getObject(ossConfig.getBucketName(), url).getObjectContent();
            return IoUtil.readBytes(inputStream);
        } catch (Exception e) {
            log.error("上传文件读取失败：", e);
        } finally {
            client.shutdown();
        }
        throw new JzRuntimeException("上传文件读取失败");
    }

    @Override
    public SysAttachment getSysAttachmentByUrl(String url) {
        return sysAttachmentService.getOne(new LambdaQueryWrapper<SysAttachment>().eq(SysAttachment::getUrlPath, url));
    }

}
